import urllib
import urllib2
import httplib
import json
import sys
import random
sys.path.append("./python")
from YP import *
from Variable import *

# Constants
STARTS_WITH_S = "startsWithS"
SUBWORD = "hasSubword"
BEGIN_END = "beginsAndEnds"
PALINDROME = "palindrome"
DOUBLE_LETTER = "doubleLetter"
END_IN_LAST_HALF = "lastLetterLastHalf"
DISTINCT_VOWELS = "distinctVowels"
MULTIPLE_OF_3 = "multipleOf3"

# True count, False count
STARTS_WITH_S_CONFUSION = [0, 0]
SUBWORD_CONFUSION = [0, 0]
BEGIN_END_CONFUSION = [0, 0]
PALINDROME_CONFUSION = [0, 0]
DOUBLE_LETTER_CONFUSION = [0, 0]
END_IN_LAST_HALF_CONFUSION = [0, 0]
DISTINCT_VOWELS_CONFUSION = [0, 0]
MULTIPLE_OF_3_CONFUSION = [0, 0]

# Rules of Text Zendo
# The word has a subword inside of it
def hasSubword(theWord):
    for i in range(len(theWord)):
        for j in range(i,len(theWord)):
            if theWord[i:j] == " " or theWord[i:j] == "" or theWord[i:j] == '\n':
                continue
            appearances = words.count(theWord[i:j]) 
            if  appearances > 0 and appearances != -1:
                YP.assertFact(Atom.a(SUBWORD), [Atom.a(theWord)])
                return 1
    return 0

# The word begins and ends with the same letter
def beginEnd(theWord):
    if theWord[0] == theWord[-1]:
        YP.assertFact(Atom.a(BEGIN_END), [Atom.a(theWord)])
        return 1
    return 0

# The word is a palindrome
def palindrome(theWord):
    if theWord == theWord[::-1]:
        YP.assertFact(Atom.a(PALINDROME), [Atom.a(theWord)])
        return 1
    return 0

# The word has a double letter
def doubleLetter(theWord):
    for i in range(len(theWord)-1):
        if theWord[i] == theWord[i+1]:
            YP.assertFact(Atom.a(DOUBLE_LETTER), [Atom.a(theWord)])
            return 1
    return 0

# The last letter is in the second half of the alphabet
def endInLastHalf(theWord):
    alphabet = "abcdefghijklmnopqrstuvwxyz"
    if alphabet.find(theWord[-1]) > 13:
        YP.assertFact(Atom.a(END_IN_LAST_HALF), [Atom.a(theWord)])
        return 1
    return 0

# The word has no repeated vowels
def distinctVowels(theWord):
    vowels = "aeiou"
    for i in range(len(vowels)):
        if theWord.count(vowels[i]) > 1:
            return 0
    YP.assertFact(Atom.a(DISTINCT_VOWELS), [Atom.a(theWord)])
    return 1

# The word's length is a multiple of 3
def multipleOf3(theWord):
    if len(theWord) % 3 == 0:
        YP.assertFact(Atom.a(MULTIPLE_OF_3), [Atom.a(theWord)])
        return 1
    return 0

def startsWithS(theWord):
    if theWord[0] == 's':
        YP.assertFact(Atom.a(STARTS_WITH_S), [Atom.a(theWord)])
        return 1
    return 0

# Build a Prolog database of our known words and the rules associated with them
fin = open("words.txt", "r")
words = []
for line in fin:
    words.append(line.rstrip())
    beginEnd(line.rstrip())
    palindrome(line.rstrip())
    doubleLetter(line.rstrip())
    endInLastHalf(line.rstrip())
    distinctVowels(line.rstrip())
    multipleOf3(line.rstrip())
    startsWithS(line.rstrip())
fin.close()

for word in words:
    hasSubword(word)

# Navigation functions
def getPageContent(url, destination):
    params = urllib.urlencode({'name': sys.argv[1]})
    con = urllib2.Request(url+destination, params)
    response = urllib2.urlopen(con)
    cookie = response.headers.get('Set-Cookie')
    reader = response.read()
    json_array = json.loads(reader)
    return json_array,cookie

def guessWord(word, status, cookie, url, destination):
    params = urllib.urlencode({'word': word, 'type': 'add', 'buddha': status})
    con = urllib2.Request(url+destination, params)
    con.add_header('cookie', cookie)
    response = urllib2.urlopen(con)
    cookie2 = response.headers.get('Set-Cookie')
    reader = response.read()
    json_array = json.loads(reader)
    return json_array,cookie2

def guessRuleGet(rule, cookie, url, destination):
    params = urllib.urlencode({'getRule': 'yes'})
    con = urllib2.Request(url+destination, params)
    con.add_header('cookie', cookie)
    response = urllib2.urlopen(con)
    cookie2 = response.headers.get('Set-Cookie')
    reader = response.read()
    json_array = json.loads(reader)
    return json_array,cookie2
    
def guessRulePost(rule, wordsAndStatus, cookie, url, destination):
    params = urllib.urlencode({'rule:': rule, 'wordsAndStatus': 'blah'})
    for key in wordsAndStatus.keys():
        params += '&' + urllib.urlencode({key: wordsAndStatus[key]})
    con = urllib2.Request(url+destination, params)
    con.add_header('cookie', cookie)
    response = urllib2.urlopen(con)
    cookie2 = response.headers.get('Set-Cookie')
    reader = response.read()
    json_array = json.loads(reader)
    return json_array,cookie2

# Game-logic functions
def applyRule(rule, word):
    if rule == SUBWORD:
        return hasSubword(word)
    elif rule == BEGIN_END:
        return beginEnd(word)
    elif rule == PALINDROME:
        return palindrome(word)
    elif rule == DOUBLE_LETTER:
        return doubleLetter(word)
    elif rule == END_IN_LAST_HALF:
        return endInLastHalf(word)
    elif rule == DISTINCT_VOWELS:
        return distinctVowels(word)
    elif rule == MULTIPLE_OF_3:
        return multipleOf3(word)
    elif rule == STARTS_WITH_S:
        return startsWithS(word)
    else:
        return -1
    
def chooseWord(words, rule=None):
    Word = Variable()
    result = []
    if rule == None:
        return random.choice(words)
    else:
        for l1 in YP.matchDynamic(Atom.a(rule), [Word]):
            result.append(Word.getValue())
        return random.choice(result)

def isBuddha(theWord):
    YP.assertFact(Atom.a("buddha"), [Atom.a(theWord)])
    
def isNotBuddha(theWord):
    YP.assertFact(Atom.a("nonbuddha"), [Atom.a(theWord)])

json_game,cookie = getPageContent("http://cs.centenary.edu", "/~jjenning/zendo-ilp-challenge/agent/zendo.php")

oldBuddha = set([])
oldNonBuddha = set([])

while ('game_status' not in json_game):
    buddha = set(json_game['buddha']).difference(oldBuddha)
    nonbuddha = set(json_game['nonbuddha']).difference(oldNonBuddha)
    
    for word in buddha:
        isBuddha(word)
        if hasSubword(word):
            SUBWORD_CONFUSION[0] += 1
        else:
            SUBWORD_CONFUSION[1] += 1
        
        if beginEnd(word):
            BEGIN_END_CONFUSION[0] += 1
        else:
            BEGIN_END_CONFUSION[1] += 1
        
        if palindrome(word):
            PALINDROME_CONFUSION[0] += 1
        else:
            PALINDROME_CONFUSION[1] += 1
            
        if doubleLetter(word):
            DOUBLE_LETTER_CONFUSION[0] += 1
        else:
            DOUBLE_LETTER_CONFUSION[1] += 1
            
        if endInLastHalf(word):
            END_IN_LAST_HALF_CONFUSION[0] += 1
        else:
            END_IN_LAST_HALF_CONFUSION[1] += 1
            
        if distinctVowels(word):
            DISTINCT_VOWELS_CONFUSION[0] += 1
        else:
            DISTINCT_VOWELS_CONFUSION[1] += 1
            
        if multipleOf3(word):
            MULTIPLE_OF_3_CONFUSION[0] += 1
        else:
            MULTIPLE_OF_3_CONFUSION[1] += 1
        
        if (startsWithS(word)):
            STARTS_WITH_S_CONFUSION[0] += 1
        else:
            STARTS_WITH_S_CONFUSION[1] += 1
    # Construct another tree
    for word in nonbuddha:
        isNotBuddha(word)
        if hasSubword(word):
            SUBWORD_CONFUSION[0] -= 1
        else:
            SUBWORD_CONFUSION[1] += 1
        
        if beginEnd(word):
            BEGIN_END_CONFUSION[0] -= 1
        else:
            BEGIN_END_CONFUSION[1] += 1
        
        if palindrome(word):
            PALINDROME_CONFUSION[0] -= 1
        else:
            PALINDROME_CONFUSION[1] += 1
            
        if doubleLetter(word):
            DOUBLE_LETTER_CONFUSION[0] -= 1
        else:
            DOUBLE_LETTER_CONFUSION[1] += 1
            
        if endInLastHalf(word):
            END_IN_LAST_HALF_CONFUSION[0] -= 1
        else:
            END_IN_LAST_HALF_CONFUSION[1] += 1
            
        if distinctVowels(word):
            DISTINCT_VOWELS_CONFUSION[0] -= 1
        else:
            DISTINCT_VOWELS_CONFUSION[1] += 1
            
        if multipleOf3(word):
            MULTIPLE_OF_3_CONFUSION[0] -= 1
        else:
            MULTIPLE_OF_3_CONFUSION[1] += 1
        
        if startsWithS(word):
            STARTS_WITH_S_CONFUSION[0] -= 1
        else:
            STARTS_WITH_S_CONFUSION[1] += 1
    
    maxNumber = 0
    maxRule = ""
    
    # Determine which rule is most likely thus far
    if STARTS_WITH_S_CONFUSION[0] > maxNumber:
        maxNumber = STARTS_WITH_S_CONFUSION[0]
        maxRule = STARTS_WITH_S
    if SUBWORD_CONFUSION[0] > maxNumber:
        maxNumber = SUBWORD_CONFUSION[0]
        maxRule = SUBWORD
    if BEGIN_END_CONFUSION[0] > maxNumber:
        maxNumber = BEGIN_END_CONFUSION[0]
        maxRule = BEGIN_END
    if PALINDROME_CONFUSION[0] > maxNumber:
        maxNumber = PALINDROME_CONFUSION[0]
        maxRule = PALINDROME
    if DOUBLE_LETTER_CONFUSION[0] > maxNumber:
        maxNumber = DOUBLE_LETTER_CONFUSION[0]
        maxRule = DOUBLE_LETTER
    if END_IN_LAST_HALF_CONFUSION[0] > maxNumber:
        maxNumber = END_IN_LAST_HALF_CONFUSION[0]
        maxRule = END_IN_LAST_HALF
    if DISTINCT_VOWELS_CONFUSION[0] > maxNumber:
        maxNumber = DISTINCT_VOWELS_CONFUSION[0]
        maxRule = DISTINCT_VOWELS
    if MULTIPLE_OF_3_CONFUSION[0] > maxNumber:
        maxNumber = MULTIPLE_OF_3_CONFUSION[0]
        maxRule = MULTIPLE_OF_3
    
    # If we have more than 10 stones, it's time to start guessing the rule
    if json_game['stones'] > 10:
        json_guess,cookie = guessRuleGet(maxRule, cookie, "http://cs.centenary.edu", "/~jjenning/zendo-ilp-challenge/agent/zendo.php")
        wordsAndStatus = {}
        for word in json_guess['words']:
            status = applyRule(maxRule, word)
            if status:
                wordsAndStatus[word] = 'buddha'
            else:
                wordsAndStatus[word]= 'nonbuddha'
        json_game,cookie = guessRulePost(maxRule, wordsAndStatus, cookie, "http://cs.centenary.edu", "/~jjenning/zendo-ilp-challenge/agent/zendo.php")
        continue
        
    oldBuddha = oldBuddha.union(buddha)
    oldNonBuddha = oldNonBuddha.union(nonbuddha)
    
    print maxRule
    guess = chooseWord(words, maxRule)
    json_game,cookie = guessWord(guess, 1, cookie, "http://cs.centenary.edu", "/~jjenning/zendo-ilp-challenge/agent/zendo.php")
    print json_game
    print "\n"
    print "\n"
print "We win because we're awesome. We're awesome because we win." 

